package com.company.thread;

import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 单线程实例
 *
 * @author jianf
 * @date 2022年11月03 14:25
 */
public class CreateThreadPollDemo {

    public static final int SLEEP_GAP = 1000;

    public static void main(String[] args) {
//        singleThreadExecutor();
//        fixedThreadPool();
        cachedThreadPool();
    }

    /**
     * 单线程化线程池
     */
    static void singleThreadExecutor() {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 3; i++) {
            pool.execute(new TargetTask());
            pool.submit(new TargetTask());
        }
        pool.shutdown();
    }

    /**
     * 固定数量的线程池
     */
    static void fixedThreadPool() {
        ExecutorService pool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 30; i++) {
            pool.execute(new TargetTask());
            pool.submit(new TargetTask());
        }
        pool.shutdown();
    }

    /**
     * 可缓存线程池
     *
     * <br>特点：
     * <li>在接收新的异步任务target执行目标实例时，如果池内所有线程繁忙，此线程池就会添加新线程来处理任务
     * <li>线程池不会对线程池大小进行限制，线程池大小完全依赖于操作系统（或者说JVM）能够创建的最大线程大小
     * <li>如果部分线程空闲，也就是存量线程的数量超过了处理任务数量，就会回收空闲（60秒不执行任务）线程</li>
     * <p>
     *
     *
     * <br>适用场景：
     * <li>需要快速处理突发性强、耗时较短的任务场景，如Netty的NIO处理场景、REST API接口的瞬时削峰场景
     *
     * <p><br>缺点：
     * <li>线程池没有最大线程数量限制，如果大量的异步任务执行目标实例同时提交，可能会因创建线程过多而导致资源耗尽
     */
    static void cachedThreadPool() {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            pool.execute(new TargetTask());
            pool.submit(new TargetTask());
        }
        pool.shutdown();
    }

    static class TargetTask implements Runnable {
        static AtomicInteger taskNo = new AtomicInteger(1);
        private String taskName;

        public TargetTask() {
            taskName = "task-" + taskNo;
            taskNo.incrementAndGet();
        }

        public void run() {
            LocalDateTime ldt = LocalDateTime.now();
            System.out.println(ldt.toString() + " - " + "任务:" + taskName + " 开始启动...");
            try {
                Thread.sleep(SLEEP_GAP);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务:" + taskName + " 结束...");
        }
    }
}
